package com.autumn.mybatis.provider.mysql.builder;

import com.autumn.mybatis.metadata.EntityTable;
import com.autumn.mybatis.provider.builder.AbstractQueryBuilder;
import com.autumn.mybatis.provider.mysql.MySqlProvider;
import com.autumn.mybatis.provider.mysql.MySqlUtils;
import com.autumn.mybatis.provider.util.MybatisSqlUtils;
import com.autumn.util.StringUtils;

/**
 * 查询生成器
 * 
 * @author 杨昌国
 *
 *         2017-10-19 08:40:15
 */
public class MySqlQueryBuilder extends AbstractQueryBuilder {

	/**
	 * 
	 * @param dbProvider
	 */
	public MySqlQueryBuilder(MySqlProvider dbProvider) {
		super(dbProvider);
	}

	/**
	 * 锁
	 * 
	 * @param lockModeName
	 * @return
	 */
	private static String lockMode(String lockModeName) {
		StringBuilder sql = new StringBuilder();
		sql.append(String.format("<if test=\"%1$s != null \">", lockModeName));
		sql.append("<choose >");
		sql.append(String.format("<when test=\"%1$s.name == 'SHARE'\">", lockModeName));
		sql.append("LOCK IN SHARE MODE");
		sql.append("</when>");
		sql.append(String.format("<when test=\"%1$s.name == 'UPDATE'\">", lockModeName));
		sql.append("FOR UPDATE");
		sql.append("</when>");
		sql.append("</choose>");
		sql.append("</if>");
		return sql.toString();
	}

	@Override
	public String getSelectByPrimaryKeyByLockSql(EntityTable table, String keyParamName, String lockModeParamName) {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT ");
		sql.append(MybatisSqlUtils.getAllColumns(table));
		sql.append(" FROM ");
		sql.append(MybatisSqlUtils.getTableOrViewName(table));
		sql.append(MybatisSqlUtils.wherePrimaryKeys(table, keyParamName));
		sql.append(lockMode(lockModeParamName));
		return sql.toString();
	}

	/**
	 * 锁查询所有
	 * 
	 * @param table
	 * @param lockModeParamName
	 * @return
	 */
	@Override
	public String getSelectAllLockSql(EntityTable table, String lockModeParamName) {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT ");
		sql.append(MybatisSqlUtils.getAllColumns(table));
		sql.append(" FROM ");
		sql.append(MybatisSqlUtils.getTableOrViewName(table));
		if (!StringUtils.isNullOrBlank(table.getOrderByClause())) {
			sql.append(" ORDER BY ");
			sql.append(table.getOrderByClause());
		}
		sql.append(lockMode(lockModeParamName));
		return sql.toString();
	}

	/**
	 * 获取根据查询全部记录条数的sql（锁）
	 * 
	 * @param table
	 * @param lockModeParamName
	 * @return
	 */
	@Override
	public String getCountByAllLockSql(EntityTable table, String lockModeParamName) {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT COUNT(*) FROM ");
		sql.append(MybatisSqlUtils.getTableOrViewName(table));
		sql.append(lockMode(lockModeParamName));
		return sql.toString();
	}

	@Override
	public String getSelectListSql(EntityTable table, String parmaName) {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT ");
		sql.append(MybatisSqlUtils.getAllColumns(table));
		sql.append(" FROM ");
		sql.append(MybatisSqlUtils.getTableOrViewName(table));
		sql.append(MySqlUtils.createSectionWhereSql(parmaName));
		sql.append(getOrder());
		sql.append(getLimit());
		sql.append(lockMode(String.format("%s.lockMode", parmaName)));
		return sql.toString();
	}

	@Override
	public String getSelectFirstSql(EntityTable table, String parmaName) {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT ");
		sql.append(MybatisSqlUtils.getAllColumns(table));
		sql.append(" FROM ");
		sql.append(MybatisSqlUtils.getTableOrViewName(table));
		sql.append(MySqlUtils.createSectionWhereSql(parmaName));
		sql.append(getOrder());
		sql.append(" LIMIT 1");
		sql.append(lockMode(String.format("%s.lockMode", parmaName)));
		return sql.toString();
	}

	@Override
	public String getCountByWhereSql(EntityTable table, String parmaName) {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT COUNT(*) FROM ");
		sql.append(MybatisSqlUtils.getTableOrViewName(table));
		sql.append(MySqlUtils.createSectionWhereSql(parmaName));
		sql.append(lockMode(String.format("%s.lockMode", parmaName)));
		return sql.toString();
	}

	private String getSelectBySpecifyBaseSql(EntityTable table, String parmaName) {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT");
		sql.append("<foreach collection=\"" + parmaName + ".selectList\" item=\"item\" separator=\",\">");
		sql.append("${item}");
		sql.append("</foreach>");
		sql.append(" FROM ");
		sql.append(MybatisSqlUtils.getTableOrViewName(table));
		sql.append(MySqlUtils.createSectionWhereSql(parmaName));
		sql.append(getOrder());
		return sql.toString();
	}

	@Override
	public String getSelectBySpecifySql(EntityTable table, String parmaName) {
		StringBuilder sql = new StringBuilder();
		sql.append(getSelectBySpecifyBaseSql(table, parmaName));
		sql.append(getLimit());
		sql.append(lockMode(String.format("%s.lockMode", parmaName)));
		return sql.toString();
	}

	@Override
	public String getSelectBySpecifyFirstSql(EntityTable table, String parmaName) {
		StringBuilder sql = new StringBuilder();
		sql.append(getSelectBySpecifyBaseSql(table, parmaName));
		sql.append(" LIMIT 1");
		sql.append(lockMode(String.format("%s.lockMode", parmaName)));
		return sql.toString();
	}

	/**
	 * 排序
	 * 
	 * @return
	 */
	private String getOrder() {
		StringBuilder sql = new StringBuilder();
		sql.append("<if test=\"section.orderClauses.size>0\">");
		sql.append("<trim prefix=\"ORDER BY\" suffixOverrides=\",\">");
		sql.append("<foreach collection=\"section.orderClauses\" item=\"item\">");
		sql.append("${item.columnName} ${item.direction}");
		sql.append(",");
		sql.append("</foreach>");
		sql.append("</trim>");
		sql.append("</if>");
		return sql.toString();
	}

	/**
	 * 分页查询
	 * 
	 * @return
	 */
	private String getLimit() {
		StringBuilder sql = new StringBuilder();
		sql.append("<choose >");
		sql.append("<when test=\"section.pageClause.offset>0 and section.pageClause.limit>0\">");
		sql.append("LIMIT #{section.pageClause.offset},#{section.pageClause.limit}");
		sql.append("</when>");
		sql.append("<when test=\"section.pageClause.offset>0\">");
		sql.append("OFFSET #{section.pageClause.offset}");
		sql.append("</when>");
		sql.append("<when test=\"section.pageClause.limit>0\">");
		sql.append("LIMIT #{section.pageClause.limit}");
		sql.append("</when>");
		sql.append("</choose>");
		return sql.toString();
	}

}
